#include "config.h"

namespace yuechuan {
    /**
     * @brief 列出当前节点的所有子节点
     * @details 为了能实现A.b = 20  ==>  A:
     * @param prefix 父节点名称              b: 20
     * @param node 父节点
     * @param out_put 子节点构成的键值对数组
     */
    static void ListAllMember(const std::string &prefix,
                              const YAML::Node &node,
                              std::list <std::pair<std::string, const YAML::Node>> &out_put) {
        if (prefix.find_first_not_of("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ._0123456789") !=
            std::string::npos) {
            YUECHUAN_LOG_ERROR(YUECHUAN_LOG_ROOT()) << "Invalid Key " << prefix << std::endl;
        }
        out_put.emplace_back(prefix, node);
        if (node.IsMap()) {
            for (auto it = node.begin(); it != node.end(); ++it) {
                ListAllMember(prefix.empty() ? it->first.Scalar() : prefix + "." + it->first.Scalar(), it->second,
                              out_put);
            }
        }
    }

    ConfigVarBase::ptr Config::LookupBase(const std::string &name) {
        RWMutexType::ReadLock lock(GetMutex());
        auto it = GetDatas().find(name);
        return it == GetDatas().end() ? nullptr : it->second;
    }

    void Config::LoadFromYaml(const YAML::Node &root) {
        std::list <std::pair<std::string, const YAML::Node>> all_list;
        ListAllMember("", root, all_list);

        for (auto &i : all_list) {
            std::string key = i.first;
            if (key.empty()) {
                continue;
            }
            std::transform(key.begin(), key.end(), key.begin(), ::tolower);
            ConfigVarBase::ptr var = LookupBase(key);

            if (var) {
                if (i.second.IsScalar()) {
                    var->fromString(i.second.Scalar());
                } else {
                    std::stringstream ss;
                    ss << i.second;
                    var->fromString(ss.str());
                }
            }
        }
    }

    void Config::Visit(std::function<void(ConfigVarBase::ptr)> cb) {
        RWMutexType::ReadLock lock(GetMutex());
        ConfigVarMap &m = GetDatas();
        for (auto it = m.begin(); it != m.end(); ++it) {
            cb(it->second);
        }
    }

} // namespace yuechuan
